package com.qf.listener;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * projectName: sms-platform02
 *
 * @author: 元
 * time: 2021/10/19 0019 14:10
 * description:监听MQ中的状态,推送给甲方项目
 */
@Component
@Slf4j
public class SmsReportListener {

    @Autowired
    private CacheFeign cacheFeign;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //消息发送的延时时间
    private static final Integer [] SMS_TTL = {0,10000,30000,60000,300000};


    //监听MQ中的状态报告队列,推动给甲方项目
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void messageHandler(StandardReport standardReport, Channel channel, Message message) throws Exception{

        //1.获取客户端ID
        long clientID = standardReport.getClientID();
        //2.从redis中获取当前用户对象
        Map clientMap = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + clientID);
        //3.从用户对象中获取将要推送的目标服务器地址
        String receivestatusurl = String.valueOf(clientMap.get("receivestatusurl"));

        //4.获取用户是否需要返回状态报告,0为不返回,1是需要返回
        String isReturnStatus = String.valueOf(clientMap.get("isreturnstatus"));

        //5.判断当前报告状态,为1则进行第一次推送
        if (!StringUtils.isEmpty(isReturnStatus) && "1".equals(isReturnStatus)) {
            //5.1设置用户接受状态报告的回调数据
            standardReport.setReceiveStatusUrl(receivestatusurl);
            //5.2设置推送次数,完成第一次推送
            standardReport.setSendCount(1);
            //5.3推送状态报告,并返回结果
            String result = null;
            result = sendReport(standardReport,result);
            //5.4判断推送报告中返回的结果,如果为空则判定推送失败,进入延时队列
            if (result == null){
                //为空,则推送失败,进入延时队列,发送次数加1
                standardReport.setSendCount(standardReport.getSendCount() + 1);
                sendDelayedMessage(standardReport);
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            }else{
                //5.5如果状态报告的推送状态为0,返回Success,则不推送
                log.info("[接口模块~状态报告推送],推送成功!");
                isSuccess(standardReport,result);
            }

        } else {
            //6.如果状态报告的推送状态为0,则不推送
            log.info("[接口模块~状态报告推送],用户决定不推送! 短信发送流程执行完毕");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        }
    }


    //状态报告发送至延时消息队列
    private void sendDelayedMessage(StandardReport standardReport){
        log.info("[接口模块~状态报告推送],将报告发送至延时消息队列");
        //判断状态报告的发送次数
        if (standardReport.getSendCount() <= 5){
            rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, "routingKey", standardReport, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    //设置状态报告在队列中的延时时间
                    message.getMessageProperties().setDelay(SMS_TTL[standardReport.getSendCount() - 1]);
                    return message;
                }
            });
        }


    }

    //发送状态报告
    public String sendReport(StandardReport standardReport,String result) throws Exception{
        try{
            //1.封装请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            //2.封装请求体,请求体中封装数据
            String josnStr =  objectMapper.writeValueAsString(standardReport);
            HttpEntity<String> httpEntity = new HttpEntity<>(josnStr, headers);
            //3.发送请求
            result = restTemplate.postForObject(standardReport.getReceiveStatusUrl(), httpEntity, String.class);
            return result;
        }catch (JsonProcessingException e){
            e.printStackTrace();
            //4.若发送异常,回进入到延时队列,继续排队等待发送
            log.info("[接口模块~状态报告推送],发送过程异常,url={},standardReport={}",standardReport.getReceiveStatusUrl(),standardReport);
          //推送失败进入延时队列,发送次数加1
            standardReport.setSendCount((standardReport.getSendCount() + 1));
            sendDelayedMessage(standardReport);
            return null;

        }

    }

    //判断推送报告是否推送成功处理方法
    public void isSuccess(StandardReport standardReport,String result) {
        if(!"SUCCESS".equalsIgnoreCase(result)){
            //进入到延时队列
            sendDelayedMessage(standardReport);
        }else {
            log.info("[接口模块~状态报告推送],推送成功!");

        }


    }

    //监听延时队列,队列中发送失败的状态报告从这里重新推送
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayedQueueHandler(StandardReport standardReport,Channel channel,Message message)throws Exception{
        //对发送次数进行计数
        standardReport.setSendCount(standardReport.getSendCount() + 1);
        //封装请求头和请求体等参数
        String result = null;
        result = sendReport(standardReport,result);
        if (result == null){
            return;
        }
        //判断是否发送成功
        isSuccess(standardReport,result);
        //返回ACK
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);



    }



}
